using System;
using System.Collections.Generic;
using System.Text;

using System.Xml.XPath;
using System.Xml.Xsl;

namespace BadHabit.Factory.Reports {

    public class BacklogReport : Report {
        

        /// <summary>
        /// Implements a Report class to generate a backlog report.
        /// </summary>
        /// <param name="factory"></param>
        public BacklogReport(Factory factory) : base(factory) {}


        /// <summary>
        /// The template type name.
        /// </summary>
        public override string TemplateTypeName {
            get {
                return "BacklogReport";
            }
        }

        /// <summary>
        /// Adjusts the dataset for XPS render.
        /// </summary>
        /// <param name="projectUId">The projectUId</param>
        /// <returns>The adjusted dataset</returns>
        public override System.Data.DataSet CreateDataSet() {
            return factory.RetriveProject(this.ProjectUId);
        }

        
        
        public override System.Data.DataSet AdjustDataSet(System.Data.DataSet report) {

            report = base.AdjustDataSet(report);

            Data.ProjectDataSet project = (Data.ProjectDataSet)report;

            project.Project.Columns.Add("BacklogEmmitionDateString", typeof(string));
            project.Project[0]["BacklogEmmitionDateString"] = DateTime.Now.ToLongDateString() + ", " + DateTime.Now.ToLongTimeString();

            project.Project.Columns.Add("EstimatedEndDateString", typeof(string));
            project.Project[0]["EstimatedEndDateString"] = project.Project[0].EstimatedEndDate.ToShortDateString();

            project.Sprint.Columns.Add("ExpirationDateString", typeof(string));
            project.Sprint.Columns.Add("StartDateString", typeof(string));
            project.Sprint.Columns.Add("ApprovalDateString", typeof(string));
            foreach (Data.ProjectDataSet.SprintRow r in project.Sprint) {
                r["StartDateString"] = MiniShortDateString(r.StartDate);
                if(!r.IsExpirationDateNull())
                    r["ExpirationDateString"] = MiniShortDateString(r.ExpirationDate);
                if(!r.IsApprovalDateNull())
                    r["ApprovalDateString"] = MiniShortDateString(r.ApprovalDate);

            }

            project.BacklogItem.Columns.Add("DeliverySprintNumber", typeof(short));
            project.BacklogItem.Columns.Add("DeliverySprintUId", typeof(string));
            foreach (Data.ProjectDataSet.BacklogItemRow item in project.BacklogItem) {
                if (item.DeliverySprint != null) {
                    item["DeliverySprintNumber"] = item.DeliverySprint.SprintNumber;
                    item["DeliverySprintUId"] = item.DeliverySprint.SprintUId;
                }
            }

            project.Project.Columns.Add("CurrentSprintUId", typeof(string));
            Data.ProjectDataSet.SprintRow currentSprint = project.Project[0].CurrentSprint;
            if(currentSprint!=null)
                project.Project[0]["CurrentSprintUId"] = currentSprint.SprintUId;

            project.Project.Columns.Add("LastSprintUId", typeof(string));
            Data.ProjectDataSet.SprintRow lastSprint = project.Project[0].LastSprint;
            if (lastSprint != null)
                project.Project[0]["LastSprintUId"] = lastSprint.SprintUId;

          
            // read all project tasks
            Data.TaskDataSet tasks = factory.RetriveProjectTasks(project.Project[0].ProjectUId, -1);

            CalcSprintSpeed(project, tasks);
            CalcProjectSpeed(project, tasks);

            AddProjectIndicators(project);

            return report;

        }


        private void AddProjectIndicators(Data.ProjectDataSet project) {
            double budgetIndicator = 0.0;
            double qualityIndicator = 0.0;
            double velocityIndicator = 0.0;
            double deadlineIndicator = 0.0;
            double walkedIndicator = 0.0;

            try {
                Data.ProjectPerformanceDataSet.ProjectPerformanceRow ind = Factory.Current.RetriveProjectPerformanceIndicators(project.Project[0].ProjectUId);
                if (ind != null) {
                    budgetIndicator = ind.PctBudgetBurned;
                    qualityIndicator = ind.PctBugEffort;
                    velocityIndicator = ind.Velocity;
                    deadlineIndicator = ind.HoursAhead;
                    walkedIndicator = ind.PctWalked;
                }
            } catch (Exception) { }

            project.Project.Columns.Add("BudgetIndicator", typeof(double));
            project.Project[0]["BudgetIndicator"] = budgetIndicator;
            project.Project.Columns.Add("QualityIndicator", typeof(double));
            project.Project[0]["QualityIndicator"] = qualityIndicator;
            project.Project.Columns.Add("VelocityIndicator", typeof(double));
            project.Project[0]["VelocityIndicator"] = velocityIndicator;
            project.Project.Columns.Add("DeadlineIndicator", typeof(double));
            project.Project[0]["DeadlineIndicator"] = deadlineIndicator;
            project.Project.Columns.Add("WalkedIndicator", typeof(double));
            project.Project[0]["WalkedIndicator"] = walkedIndicator;
        }

        private void CalcSprintSpeed(Data.ProjectDataSet project, Data.TaskDataSet tasks) {
            
            if(!project.Sprint.Columns.Contains("Speed"))
                project.Sprint.Columns.Add("Speed", typeof(double));


            

            foreach (Data.ProjectDataSet.SprintRow r in project.Sprint.Select("","SprintNumber")) {

                string doneFilter = "status=2 and StartDate >= '" + r.StartDate.ToShortDateString() + "' and FinishDate <= '" + r.ExpirationDate.ToShortDateString() + "'";
                
                string doneBacklogItemUIds = "";
                foreach (Data.ProjectDataSet.BacklogItemRow s in project.BacklogItem.Select(doneFilter))
                    doneBacklogItemUIds = doneBacklogItemUIds + ",'" + s.BacklogItemUId + "'";

                double sprintSize = 0;
                double.TryParse(project.BacklogItem.Compute("SUM(Size)", doneFilter).ToString(), out sprintSize);

                double sprintEffort = 0;
                if(doneBacklogItemUIds.Length>0)                     
                    double.TryParse(tasks.Task.Compute("SUM(ActualEffort)", "BacklogItemUId IN (" + doneBacklogItemUIds.Substring(1) + ")").ToString(), out sprintEffort);

                if (sprintEffort > 0)
                    r["Speed"] = sprintSize / sprintEffort;
                else
                    r["Speed"] = 0;
                
            

            }
        }

        private void CalcProjectSpeed(Data.ProjectDataSet project, Data.TaskDataSet tasks) {

            if (!project.Project.Columns.Contains("Speed"))
                project.Project.Columns.Add("Speed", typeof(double));

            
            string doneFilter = "status=2";

            double size = 0;
            double.TryParse(project.BacklogItem.Compute("SUM(Size)", doneFilter).ToString(), out size);

            double effort = 0;
            double.TryParse(tasks.Task.Compute("SUM(ActualEffort)", "").ToString(), out effort);

            if (effort > 0)
                project.Project[0]["Speed"] = size / effort;
            else
                project.Project[0]["Speed"] = 0;

        }

      

       


        
    }
}
